package XMLtoJSON;

import Utils.Env;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.*;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class ParseXML {
    public static void main(String[] args) throws FileNotFoundException {
        Env.print();
//        useDOM();
//        useSAX();
//        useJackson();
        useJson();
    }

    private static void useSAX() {
        try {
            InputStream input = ParseXML.class.getResourceAsStream("book.xml");
            SAXParserFactory spf = SAXParserFactory.newInstance();
            SAXParser saxParser = spf.newSAXParser();
            saxParser.parse(input, new MyHandler());
        } catch (Exception exception) {
            System.out.println("SAX -> " + exception.getMessage());
        }
    }


    private static class MyHandler extends DefaultHandler {
        public void startDocument() throws SAXException {
            print("start document");
        }

        public void endDocument() throws SAXException {
            print("end document");
        }

        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            print("start element:", localName, qName);
        }

        public void endElement(String uri, String localName, String qName) throws SAXException {
            print("end element:", localName, qName);
        }

        public void characters(char[] ch, int start, int length) throws SAXException {
            print("characters:", new String(ch, start, length));
        }

        public void error(SAXParseException e) throws SAXException {
            print("error:", e);
        }

        void print(Object... objs) {
            for (Object obj : objs) {
                System.out.print(obj);
                System.out.print(" ");
            }
            System.out.println();
        }
    }

    private static void useDOM() {
        //        assert path != null;
        try {
            //      1. class 目录下的文件
//        InputStream input = ParseXML.class.getResourceAsStream("book.xml");

            // 2. 取工作区路径  当前工作目录: F:\Repositories\JAVA_LEARN\Basic
//        InputStream input = new FileInputStream("./out/production/Basic/book.xml");
            // 3. 绝对路径
            InputStream input = new FileInputStream("F:/Repositories/JAVA_LEARN/Basic/out/production/Basic/book.xml");
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse(input);
            Node root = doc.getDocumentElement();
            printNode(root, 4);
//            NodeList nodeList = root.getChildNodes();
//            int length = nodeList.getLength();
//            for (int i =0; i < length; ++i) {
//                printNode(nodeList.item(i), 8);
//            }
        } catch (ParserConfigurationException | SAXException | IOException exception) {
            System.out.println("ParseXML error -> " + exception.getMessage());
        }
    }

    private static void printNode(Node n, int indent) {
        for (int i = 0; i < indent; i++) {
            System.out.print(' ');
        }
        switch (n.getNodeType()) {
            case Node.DOCUMENT_NODE: // Document节点
                System.out.println("Document: " + n.getNodeName());
                break;
            case Node.ELEMENT_NODE: // 元素节点
                System.out.println("Element: " + n.getNodeName());
                break;
            case Node.TEXT_NODE: // 文本
                System.out.println("Text: " + n.getNodeName() + " = " + n.getNodeValue());
                break;
            case Node.ATTRIBUTE_NODE: // 属性
                System.out.println("Attr: " + n.getNodeName() + " = " + n.getNodeValue());
                break;
            default: // 其他
                System.out.println("NodeType: " + n.getNodeType() + ", NodeName: " + n.getNodeName());
        }
        for (Node child = n.getFirstChild(); child != null; child = child.getNextSibling()) {
            printNode(child, indent + 1);
        }
    }

    // xml to JavaBean  Jackson
    private static void useJackson() {
        try {
            InputStream input = ParseXML.class.getResourceAsStream("book.xml");
            JacksonXmlModule module = new JacksonXmlModule();
            XmlMapper mapper = new XmlMapper(module);
            Book book = mapper.readValue(input, Book.class);
            System.out.println(book);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    // javabean all properties must be public...
    private static class Book {
        public long id;
        public String name;
        public String author;
        public String isbn;
        public List<String> tags;
        public String publishDate;

        public Double price;

        public String publisher;

        public long size;

        public String edition;

        public Chapter[] chapters;


        @Override
        public String toString() {
            StringBuilder chapters = new StringBuilder();
            for (Chapter chapter : this.chapters) {
                chapters.append(chapter.title);
            }
            return this.id +
                    "#" +
                    this.name +
                    "#" +
                    this.author +
                    "#" +
                    this.isbn +
                    "#" +
                    this.tags +
                    "#" +
                    this.publishDate + "#" + chapters.toString();
        }
    }

    private static class Chapter {
        public String title;
    }

    private static void useJson() {
        InputStream input = ParseXML.class.getResourceAsStream("book.json");

        // resolve to Internal Exception: java.lang.NoClassDefFoundError: com.fasterxml.jackson.databind.ObjectMapper
        // com.fasterxml.jackson.core:jackson-databind:2.9.0
        ObjectMapper mapper = new ObjectMapper();
        // 反序列化时忽略不存在的JavaBean属性:
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        try {
            Book2 book = mapper.readValue(input, Book2.class);
            System.out.println(book);
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }

    }

    private static class Book2 {
        public long id;
        public String name;
        public String isbn;
        public List<String> tags;

        public Author author;
    }

    private static class Author {
        public String firstName;
        public String lastName;
    }
}
